package common

//此部分是专门针对http统计，从common里剥离出来的

import (
	"encoding/json"
	"fmt"
	"os"
	"sort"
	"strings"
	"sync"
)

var mutex sync.RWMutex

type DistMain struct {
	XName    []string     `json:"xname"`
	Subvalue []CountItemh `json:"subvalue"`
}

// 用于对合计结果进行排序的数据结构
type CountItemh struct {
	Name  string `json:"name"`
	Value int64  `json:"value"`
}

// 用于对合计结果进行排序的数据结构
type CountItemh2 struct {
	Name    string `json:"name"`
	Percent string `json:"percent"`
	Value   int64  `json:"value"`
}

// 排序数据结构
type ByCounth []CountItemh

func (c ByCounth) Len() int           { return len(c) }
func (c ByCounth) Swap(i, j int)      { c[i], c[j] = c[j], c[i] }
func (c ByCounth) Less(i, j int) bool { return c[i].Value > c[j].Value }

// 排序并打印合计的数据项字典
func PrintMapjson(m map[string]int64, base int64, top int, islist bool) string {
	var bc ByCounth = make([]CountItemh, 0, len(m))
	var bbc = make([]CountItemh, 0, len(m))
	var bbc2 = make([]CountItemh2, 0, len(m))
	var dname []string

	mutex.Lock()
	defer mutex.Unlock()
	for k, v := range m {
		bc = append(bc, *&CountItemh{k, v})
	}

	sort.Sort(bc)

	for i, v := range bc {
		if islist {
			xpercet := fmt.Sprintf("%.3f", float64(v.Value)/float64(base)*100)
			bbc2 = append(bbc2, *&CountItemh2{strings.Replace(v.Name, "%", "%%", -1), xpercet, v.Value})
		} else {
			dname = append(dname, v.Name)
			bbc = append(bbc, *&CountItemh{v.Name, v.Value})
		}
		if i > top {
			break
		}
	}

	if islist {
		jsonStr, err := json.Marshal(bbc2)
		if err != nil {
			fmt.Println(err)
		}
		return fmt.Sprintf("%s", jsonStr)
	} else {
		aaa := &DistMain{
			XName:    dname,
			Subvalue: bbc,
		}
		jsonStr, err := json.Marshal(aaa)
		if err != nil {
			fmt.Println(err)
		}
		return fmt.Sprintf("%s", jsonStr)
	}
}

// 计数器对象
type CounterHttp struct {
	MapHttp map[string]int64
}

// 新建计数器对象实例
func NewCounterHttp() *CounterHttp {
	return &CounterHttp{
		MapHttp: make(map[string]int64, 60),
	}
}

//统计指定字段发送字节的大小
func (c *CounterHttp) CountHttpBytes(l *Log, k string) {
	//k := log.Host
	v, ok := c.MapHttp[k]
	if ok {
		mutex.Lock()
		defer mutex.Unlock()
		c.MapHttp[k] = v + l.BodyBytes
	} else {
		mutex.Lock()
		defer mutex.Unlock()
		c.MapHttp[k] = l.BodyBytes
	}
	//fmt.Println(k, ok)
}

// 排序并打印合计的数据项字典
func PrintMapjson2(m map[string]int64, base int64, top int) string {
	var bc ByCounth = make([]CountItemh, 0, len(m))
	var bbc2 = make([]CountItemh2, 0, len(m))
	mutex.Lock()
	defer mutex.Unlock()
	for k, v := range m {
		bc = append(bc, *&CountItemh{k, v})
	}

	sort.Sort(bc)

	for i, v := range bc {
		xpercet := fmt.Sprintf("%.3f", float64(v.Value)/float64(base)*100)
		bbc2 = append(bbc2, *&CountItemh2{v.Name, xpercet, v.Value})
		if i > top {
			break
		}
	}

	jsonStr, err := json.Marshal(bbc2)
	if err != nil {
		fmt.Println(err)
	}
	return fmt.Sprintf("%s", jsonStr)

}

func (c *TrendCounter) CountHttp(log *Log, t string) {
	mutex.Lock()
	defer mutex.Unlock()
	var k string
	IpMap["127.0.0.1"] = "1"
	switch t {
	case "m":
		k = log.TimeLocal[12:17]
	case "s":
		k = log.TimeLocal[12:20]
	case "hour":
		k = log.TimeLocal[0:14]
	case "d":
		k = log.TimeLocal[0:11]
	case "r":
		k = log.Uri
	case "a":
		k = log.UserAgent
	case "e":
		k = log.Referer
	case "h":
		k = log.RemoteAddr
	case "i":
		k = log.RawUri
	case "U":
		k = log.BackHost
	case "x":
		k = log.XForwardFor
	case "R":
		k = log.XRealIP
	case "n":
		k = log.CremoteAddr
	case "w":
		k = log.Scheme
	case "H":
		k = log.Host
	case "md":
		k = log.Method
	default:
		fmt.Println("Trend arugs no support " + t)
		os.Exit(1)
	}

	v, ok := c.MapC[k]
	if ok {
		c.MapC[k] = v + 1
	} else {
		c.MapC[k] = 1
	}

	//统计UserAgent

	Baiduspider, ok := c.MapBaiduspider[k]
	Spider360, _ := c.MapSpider360[k]
	Sogouspider, _ := c.MapSogouspider[k]
	Googlebot, _ := c.MapGooglebot[k]
	Sosospider, _ := c.MapSosospider[k]
	YisouSpider, _ := c.MapYisouSpider[k]

	UCBrowser, _ := c.MapUCBrowser[k]
	MicroMessenger, _ := c.MapMicroMessenger[k]
	MQQBrowser, _ := c.MapMQQBrowser[k]
	Maxthon, _ := c.MapMaxthon[k]
	QQBrowser, _ := c.MapQQBrowser[k]
	LBBROWSER, _ := c.MapLBBROWSER[k]
	SE360, _ := c.MapSE360[k]

	msie, _ := c.Mapmsie[k]
	chrome, _ := c.Mapchrome[k]
	firefox, _ := c.Mapfirefox[k]
	safari, _ := c.Mapsafari[k]
	OtherUa, _ := c.MapOtherUa[k]

	if ok {
		switch {
		//爬虫，由于存在包含关系，需要严格按照顺序爬虫ua--移动端[uc|android|ios]---tx,360,liebao---pc端[chrome,msie,firefox,safari]
		case strings.Contains(log.UserAgent, "Baiduspider"):
			c.MapBaiduspider[k] = Baiduspider + 1
		case strings.Contains(log.UserAgent, "360Spider"):
			c.MapSpider360[k] = Spider360 + 1
		case strings.Contains(log.UserAgent, "Sogou web spider"):
			c.MapSogouspider[k] = Sogouspider + 1
		case strings.Contains(log.UserAgent, "Googlebot"):
			c.MapGooglebot[k] = Googlebot + 1
		case strings.Contains(log.UserAgent, "Sosospider"):
			c.MapSosospider[k] = Sosospider + 1
		case strings.Contains(log.UserAgent, "YisouSpider"):
			c.MapYisouSpider[k] = YisouSpider + 1
			//移动浏览器
		case strings.Contains(log.UserAgent, "UCBrowser"):
			c.MapUCBrowser[k] = UCBrowser + 1
		case strings.Contains(log.UserAgent, "MicroMessenger"):
			c.MapMicroMessenger[k] = MicroMessenger + 1
		case strings.Contains(log.UserAgent, "MQQBrowser"):
			c.MapMQQBrowser[k] = MQQBrowser + 1
			//pc浏览器
		case strings.Contains(log.UserAgent, "Maxthon"):
			c.MapMaxthon[k] = Maxthon + 1
		case strings.Contains(log.UserAgent, "QQBrowser"):
			c.MapQQBrowser[k] = QQBrowser + 1
		case strings.Contains(log.UserAgent, "LBBROWSER"):
			c.MapLBBROWSER[k] = LBBROWSER + 1
		case strings.Contains(log.UserAgent, "360SE") || strings.Contains(log.UserAgent, "360EE"): //360浏览会屏蔽自己的标识
			c.MapSE360[k] = SE360 + 1

		case strings.Contains(log.UserAgent, "MSIE"):
			c.Mapmsie[k] = msie + 1
		case strings.Contains(log.UserAgent, "Chrome"):
			c.Mapchrome[k] = chrome + 1
		case strings.Contains(log.UserAgent, "Firefox"):
			c.Mapfirefox[k] = firefox + 1
		case strings.Contains(log.UserAgent, "Safari"):
			c.Mapsafari[k] = safari + 1
		default:
			c.MapOtherUa[k] = OtherUa + 1
		}
	} else {
		//爬虫
		c.MapBaiduspider[k] = 0
		c.MapSpider360[k] = 0
		c.MapSogouspider[k] = 0
		c.MapGooglebot[k] = 0
		c.MapSosospider[k] = 0
		c.MapYisouSpider[k] = 0
		//移动浏览器
		c.MapUCBrowser[k] = 0
		c.MapMicroMessenger[k] = 0
		c.MapMQQBrowser[k] = 0
		//pc浏览器
		c.MapMaxthon[k] = 0
		c.MapQQBrowser[k] = 0
		c.MapLBBROWSER[k] = 0

		c.Mapmsie[k] = 0
		c.Mapchrome[k] = 0
		c.Mapfirefox[k] = 0
		c.Mapsafari[k] = 0
		c.MapOtherUa[k] = 0
	}

	//统计状态码
	vs200, ok := c.Map200[k]
	vs301, _ := c.Map301[k]
	vs302, _ := c.Map302[k]
	vs400, _ := c.Map400[k]
	vs403, _ := c.Map403[k]
	vs404, _ := c.Map404[k]
	vs499, _ := c.Map499[k]
	vs500, _ := c.Map500[k]
	vs502, _ := c.Map502[k]
	vs503, _ := c.Map503[k]
	vs504, _ := c.Map504[k]

	if ok {
		switch log.StatusCode {
		case 200:
			c.Map200[k] = vs200 + 1
		case 301:
			c.Map301[k] = vs301 + 1
		case 302:
			c.Map302[k] = vs302 + 1
		case 400:
			c.Map400[k] = vs400 + 1
		case 403:
			c.Map403[k] = vs403 + 1
		case 404:
			c.Map404[k] = vs404 + 1
		case 499:
			c.Map499[k] = vs499 + 1
		case 500:
			c.Map500[k] = vs500 + 1
		case 502:
			c.Map502[k] = vs502 + 1
		case 503:
			c.Map503[k] = vs503 + 1
		case 504:
			c.Map504[k] = vs504 + 1
		}
	} else {
		c.Map200[k] = 0
		c.Map301[k] = 0
		c.Map302[k] = 0
		c.Map403[k] = 0
		c.Map400[k] = 0
		c.Map404[k] = 0
		c.Map499[k] = 0
		c.Map500[k] = 0
		c.Map502[k] = 0
		c.Map503[k] = 0
		c.Map504[k] = 0
	}

	//统计每分钟多少个remoteaddress
	vi, ok := c.MapIp[k]
	if ok {
		_, ok2 := IpMap[log.RemoteAddr]
		if ok2 {
			c.MapIp[k] = vi + 0
		} else {
			IpMap[log.RemoteAddr] = "1"
			c.MapIp[k] = vi + 1
		}
	} else {
		c.MapIp[k] = 0
		IpMap = make(map[string]string)
	}

	//统计字节
	v, ok = c.MapB[k]
	if ok {
		c.MapB[k] = v + log.BodyBytes
	} else {
		c.MapB[k] = log.BodyBytes
	}

	vt, ok := c.MapT[k]
	if ok {
		c.MapT[k] = vt + log.TimeSeconds
	} else {
		c.MapT[k] = vt
	}

	mt, ok := c.MapMaxT[k]
	if ok {
		if log.TimeSeconds > mt {
			c.MapMaxT[k] = log.TimeSeconds
		}
	} else {
		c.MapMaxT[k] = log.TimeSeconds
	}
}

//以下是将counthttp的数据json输出

//int64
type Jsmain struct {
	//XName    []string `json:"xname"`
	Dtime    []string `json:"dtime"`
	Subvalue []Svalue `json:"subvalue"`
}
type Svalue struct {
	Name  string  `json:"name"`
	Type  string  `json:"type"`
	Stack string  `json:"stack"`
	Data  []int64 `json:"data"`
}

//float64
type Jsmain2 struct {
	//XName    []string  `json:"xname"`
	Dtime    []string  `json:"dtime"`
	Subvalue []Svalue2 `json:"subvalue"`
}

type Svalue2 struct {
	Name  string    `json:"name"`
	Type  string    `json:"type"`
	Stack string    `json:"stack"`
	Data  []float64 `json:"data"`
}

var MapUa map[string][]int64
var MapSc map[string][]int64
var Dt = []string{}

var MapTime map[string][]float64
var MapCip map[string][]int64
var MapByte map[string][]float64

//MapVt = make(map[string][]float64)

func (c *TrendCounter) StatusCodeTrend(codelist string) string {
	mutex.Lock()
	defer mutex.Unlock()
	MapSc = make(map[string][]int64)
	Dt = make([]string, 0)
	minutes := make([]string, 0)

	for i, _ := range c.MapT {
		minutes = append(minutes, i)
	}

	sort.Strings(minutes)

	for _, i := range minutes {
		vc, _ := c.MapC[i]
		s200, _ := c.Map200[i]
		s301, _ := c.Map301[i]
		s302, _ := c.Map302[i]
		s400, _ := c.Map400[i]
		s403, _ := c.Map403[i]
		s404, _ := c.Map404[i]
		s499, _ := c.Map499[i]
		s500, _ := c.Map500[i]
		s502, _ := c.Map502[i]
		s503, _ := c.Map503[i]
		s504, _ := c.Map504[i]

		Dt = append(Dt, i)
		for _, code := range strings.Split(codelist, ",") {
			switch code {
			case "200":
				MapSc["200"] = append(MapSc["200"], s200)
			case "301":
				MapSc["301"] = append(MapSc["301"], s301)
			case "302":
				MapSc["302"] = append(MapSc["302"], s302)
			case "400":
				MapSc["400"] = append(MapSc["400"], s400)
			case "403":
				MapSc["403"] = append(MapSc["403"], s403)
			case "404":
				MapSc["404"] = append(MapSc["404"], s404)
			case "499":
				MapSc["499"] = append(MapSc["499"], s499)
			case "500":
				MapSc["500"] = append(MapSc["500"], s500)
			case "502":
				MapSc["502"] = append(MapSc["502"], s502)
			case "503":
				MapSc["503"] = append(MapSc["503"], s503)
			case "504":
				MapSc["504"] = append(MapSc["504"], s504)
			case "30x":
				MapSc["30x"] = append(MapSc["30x"], s301+s302)
			case "40x":
				MapSc["40x"] = append(MapSc["40x"], s400+s403+s404+s499)
			case "50x":
				MapSc["50x"] = append(MapSc["50x"], s500+s502+s503+s504)
			case "total":
				MapSc["total"] = append(MapSc["total"], vc)
			default:
				fmt.Println("nostatuscode")
			}
		}
	}
	var bbb = make([]Svalue, 0, len(MapSc))

	for kk, vv := range MapSc {
		bbb = append(bbb, *&Svalue{kk, "line", kk, vv})
	}

	aaa := &Jsmain{
		//XName:    []string{"total", "200", "301", "302", "400", "403", "404", "499", "500", "502", "503", "504"},
		Dtime:    Dt,
		Subvalue: bbb,
	}

	jsonStr, err := json.Marshal(aaa)
	if err != nil {
		fmt.Println(err)
	}
	//fmt.Printf("%s", jsonStr)
	return fmt.Sprintf("%s", jsonStr)
}

func (c *TrendCounter) UserAgentTrend(ualist string) string {
	mutex.Lock()
	defer mutex.Unlock()
	MapUa = make(map[string][]int64)
	Dt = make([]string, 0)
	minutes := make([]string, 0)

	for i, _ := range c.MapT {
		minutes = append(minutes, i)
	}

	sort.Strings(minutes)

	for _, i := range minutes {
		vc, _ := c.MapC[i]
		Baiduspider, _ := c.MapBaiduspider[i]
		Spider360, _ := c.MapSpider360[i]
		Sogouspider, _ := c.MapSogouspider[i]
		Googlebot, _ := c.MapGooglebot[i]
		Sosospider, _ := c.MapSosospider[i]
		YisouSpider, _ := c.MapYisouSpider[i]
		UCBrowser, _ := c.MapUCBrowser[i]
		MicroMessenger, _ := c.MapMicroMessenger[i]
		MQQBrowser, _ := c.MapMQQBrowser[i]
		//Maxthon, _ := c.MapMaxthon[i]
		//QQBrowser, _ := c.MapQQBrowser[i]
		//LBBROWSER, _ := c.MapLBBROWSER[i]
		//SE360, _ := c.MapSE360[i]
		msie, _ := c.Mapmsie[i]
		chrome, _ := c.Mapchrome[i]
		firefox, _ := c.Mapfirefox[i]
		safari, _ := c.Mapsafari[i]
		OtherUa, _ := c.MapOtherUa[i]

		Dt = append(Dt, i)
		for _, ua := range strings.Split(ualist, ",") {
			switch ua {
			case "baiduspider":
				MapUa["Baiduspider"] = append(MapUa["Baiduspider"], Baiduspider)
			case "spider360":
				MapUa["Spider360"] = append(MapUa["Spider360"], Spider360)
			case "sogouspider":
				MapUa["Sogouspider"] = append(MapUa["Sogouspider"], Sogouspider)
			case "googlebot":
				MapUa["Googlebot"] = append(MapUa["Googlebot"], Googlebot)
			case "sosospider":
				MapUa["Sosospider"] = append(MapUa["Sosospider"], Sosospider)
			case "yisouSpider":
				MapUa["YisouSpider"] = append(MapUa["YisouSpider"], YisouSpider)
			case "ucbrowser":
				MapUa["UCBrowser"] = append(MapUa["UCBrowser"], UCBrowser)
			case "micromessenger":
				MapUa["MicroMessenger"] = append(MapUa["MicroMessenger"], MicroMessenger)
			case "mqqbrowser":
				MapUa["MQQBrowser"] = append(MapUa["MQQBrowser"], MQQBrowser)
				/*
					case "maxthon":
						MapUa["Maxthon"] = append(MapUa["Maxthon"], Maxthon)
					case "qqbrowser":
						MapUa["QQBrowser"] = append(MapUa["QQBrowser"], QQBrowser)
					case "lbbrowser":
						MapUa["LBBROWSER"] = append(MapUa["LBBROWSER"], LBBROWSER)
					case "se360":
						MapUa["SE360"] = append(MapUa["SE360"], SE360)
				*/
			case "msie":
				MapUa["msie"] = append(MapUa["msie"], msie)
			case "chrome":
				MapUa["chrome"] = append(MapUa["chrome"], chrome)
			case "firefox":
				MapUa["firefox"] = append(MapUa["firefox"], firefox)
			case "safari":
				MapUa["safari"] = append(MapUa["safari"], safari)
			case "otherua":
				MapUa["OtherUa"] = append(MapUa["OtherUa"], OtherUa)
			case "total":
				MapUa["total"] = append(MapUa["total"], vc)
			default:
				fmt.Println("nostatuscode")
			}
		}

	}
	var bbb = make([]Svalue, 0, len(MapUa))
	for kk, vv := range MapUa {
		bbb = append(bbb, *&Svalue{kk, "line", kk, vv})
	}

	aaa := &Jsmain{
		//XName: []string{"total", "Baiduspider", "Spider360", "Sogouspider", "Googlebot",
		//	"Sosospider", "YisouSpider", "UCBrowser", "MicroMessenger",
		//	"MQQBrowser", "Maxthon", "QQBrowser", "LBBROWSER", "SE360",
		//	"msie", "chrome", "firefox", "safari", "OtherUa"},
		Dtime:    Dt,
		Subvalue: bbb,
	}

	jsonStr, err := json.Marshal(aaa)
	if err != nil {
		fmt.Println(err)
	}
	//fmt.Printf("%s", jsonStr)
	return fmt.Sprintf("%s", jsonStr)
}

func (c *TrendCounter) VtimeTrend() string {
	mutex.Lock()
	defer mutex.Unlock()
	var min float64 = 3600.0
	var max float64 = 0.0

	MapTime = make(map[string][]float64)
	Dt = make([]string, 0)
	minutes := make([]string, 0)

	for i, _ := range c.MapT {
		minutes = append(minutes, i)
		t, ok := c.MapT[i]
		if ok {
			cc, _ := c.MapC[i]
			at := t / float64(cc)
			if min > at {
				min = at
			}
			if max < at {
				max = at
			}
		}
	}

	sort.Strings(minutes)

	for _, i := range minutes {
		vc, _ := c.MapC[i]
		vt, _ := c.MapT[i]
		mt, _ := c.MapMaxT[i]
		Dt = append(Dt, i)
		MapTime["MaxTime"] = append(MapTime["MaxTime"], mt)
		MapTime["AverageTime"] = append(MapTime["AverageTime"], vt/float64(vc))
	}
	var bbb = make([]Svalue2, 0, len(MapTime))

	for kk, vv := range MapTime {
		bbb = append(bbb, *&Svalue2{kk, "line", kk, vv})
	}

	aaa := &Jsmain2{
		//XName:    []string{"MaxTime", "AverageTime"},
		Dtime:    Dt,
		Subvalue: bbb,
	}

	jsonStr, err := json.Marshal(aaa)
	if err != nil {
		fmt.Println(err)
	}
	//fmt.Printf("%s", jsonStr)
	return fmt.Sprintf("%s", jsonStr)
}

func (c *TrendCounter) CipTrend() string {
	mutex.Lock()
	defer mutex.Unlock()
	var min float64 = 3600.0
	var max float64 = 0.0

	MapCip = make(map[string][]int64)
	Dt = make([]string, 0)
	minutes := make([]string, 0)

	for i, _ := range c.MapT {
		minutes = append(minutes, i)
		t, ok := c.MapT[i]
		if ok {
			cc, _ := c.MapC[i]
			at := t / float64(cc)
			if min > at {
				min = at
			}
			if max < at {
				max = at
			}
		}
	}

	sort.Strings(minutes)

	for _, i := range minutes {
		cip, _ := c.MapIp[i]
		Dt = append(Dt, i)
		MapCip["TotalIp"] = append(MapCip["TotalIp"], cip)

	}
	var bbb = make([]Svalue, 0, len(MapCip))
	for kk, vv := range MapCip {
		bbb = append(bbb, *&Svalue{kk, "line", kk, vv})
	}

	aaa := &Jsmain{
		//XName:    []string{"TotalIp"},
		Dtime:    Dt,
		Subvalue: bbb,
	}

	jsonStr, err := json.Marshal(aaa)
	if err != nil {
		fmt.Println(err)
	}
	//fmt.Printf("%s", jsonStr)
	return fmt.Sprintf("%s", jsonStr)
}

func (c *TrendCounter) ByteTrend() string {
	mutex.Lock()
	defer mutex.Unlock()
	var min float64 = 3600.0
	var max float64 = 0.0

	MapByte = make(map[string][]float64)
	Dt = make([]string, 0)

	minutes := make([]string, 0)

	for i, _ := range c.MapT {
		minutes = append(minutes, i)
		t, ok := c.MapT[i]
		if ok {
			cc, _ := c.MapC[i]
			at := t / float64(cc)
			if min > at {
				min = at
			}
			if max < at {
				max = at
			}
		}
	}

	sort.Strings(minutes)

	for _, i := range minutes {
		vb, _ := c.MapB[i]
		Dt = append(Dt, i)
		MapByte["BodyBytes"] = append(MapByte["BodyBytes"], float64(vb)/1024/1024)
	}
	var bbb = make([]Svalue2, 0, len(MapByte))
	for kk, vv := range MapByte {
		bbb = append(bbb, *&Svalue2{kk, "line", kk, vv})
	}

	aaa := &Jsmain2{
		//XName:    []string{"BodyBytes"},
		Dtime:    Dt,
		Subvalue: bbb,
	}

	jsonStr, err := json.Marshal(aaa)
	if err != nil {
		fmt.Println(err)
	}
	//fmt.Printf("%s", jsonStr)
	return fmt.Sprintf("%s", jsonStr)
}
